home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 10
/
AACD 10.iso
/
AACD
/
Games
/
MAME
/
src
/
cpu
/
tms32010
/
tms32010.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-04-23
|
28KB
|
922 lines
/****************************************************************************
* Texas Instruments TMS320C10 DSP Emulator *
* *
* Copyright (C) 1999 by Quench *
* You are not allowed to distribute this software commercially. *
* Written for the MAME project. *
* *
* NOTES : The term 'DMA' within this document, is in reference *
* to Direct Memory Addressing, and NOT the usual term *
* of Direct Memory Access. *
* This is a word based microcontroller. *
* *
**************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "driver.h"
#include "cpuintrf.h"
#include "mamedbg.h"
#include "tms32010.h"
#define M_RDROM(A) TMS320C10_ROM_RDMEM(A)
#define M_WRTROM(A,V) TMS320C10_ROM_WRMEM(A,V)
#define M_RDRAM(A) TMS320C10_RAM_RDMEM(A)
#define M_WRTRAM(A,V) TMS320C10_RAM_WRMEM(A,V)
#define M_RDOP(A) TMS320C10_RDOP(A)
#define M_RDOP_ARG(A) TMS320C10_RDOP_ARG(A)
#define M_IN(A) TMS320C10_In(A)
#define M_OUT(A,V) TMS320C10_Out(A,V)
#define ADDR_MASK TMS320C10_ADDR_MASK
#ifndef INLINE
#define INLINE static inline
#endif
typedef struct
{
UINT16 PREPC; /* previous program counter */
UINT16 PC;
INT32 ACC, Preg;
INT32 ALU;
UINT16 Treg;
UINT16 AR[2], STACK[4], STR;
int pending_irq, BIO_pending_irq;
int irq_state;
int (*irq_callback)(int irqline);
} tms320c10_Regs;
/******** The following is the Status (Flag) register definition. *********/
/* 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
/* OV | OVM | INTM | 1 | 1 | 1 | 1 | ARP | 1 | 1 | 1 | 1 | 1 | 1 | 1 | DP */
#define OV_FLAG 0x8000 /* OV (Overflow flag) 1 indicates an overflow */
#define OVM_FLAG 0x4000 /* OVM (Overflow Mode bit) 1 forces ACC overflow to greatest positive or negative saturation value */
#define INTM_FLAG 0x2000 /* INTM (Interrupt Mask flag) 0 enables maskable interrupts */
#define ARP_REG 0x0100 /* ARP (Auxiliary Register Pointer) */
#define DP_REG 0x0001 /* DP (Data memory Pointer (bank) bit) */
static UINT8 tms320c10_reg_layout[] = {
TMS320C10_PC,TMS320C10_SP,TMS320C10_STR,TMS320C10_ACC,-1,
TMS320C10_PREG,TMS320C10_TREG,TMS320C10_AR0,TMS320C10_AR1,-1,
TMS320C10_STK0,TMS320C10_STK1,TMS320C10_STK2,TMS320C10_STK3,0
};
static UINT8 tms320c10_win_layout[] = {
28, 0,52, 4, /* register window (top rows) */
0, 0,27,22, /* disassembler window (left colums) */
28, 5,52, 8, /* memory #1 window (right, upper middle) */
28,14,52, 8, /* memory #2 window (right, lower middle) */
0,23,80, 1, /* command line window (bottom rows) */
};
static UINT16 opcode=0;
static UINT8 opcode_major=0, opcode_minor, opcode_minr; /* opcode split into MSB and LSB */
static tms320c10_Regs R;
int tms320c10_ICount;
static INT32 tmpacc;
typedef void (*opcode_fn) (void);
#define OV ( R.STR & OV_FLAG) /* OV (Overflow flag) */
#define OVM ( R.STR & OVM_FLAG) /* OVM (Overflow Mode bit) 1 indicates an overflow */
#define INTM ( R.STR & INTM_FLAG) /* INTM (Interrupt enable flag) 0 enables maskable interrupts */
#define ARP ((R.STR & ARP_REG) >> 8 ) /* ARP (Auxiliary Register Pointer) */
#define DP ((R.STR & DP_REG) << 7) /* DP (Data memory Pointer bit) */
#define dma (DP | (opcode_minor & 0x07f)) /* address used in direct memory access operations */
#define dmapage1 (0x80 | opcode_minor) /* address used in direct memory access operations for sst instruction */
#define ind (R.AR[ARP] & 0x00ff) /* address used in indirect memory access operations */
UINT16 memaccess;
#define memacc (memaccess = (opcode_minor & 0x80) ? ind : dma)
INLINE void CLR(UINT16 flag) { R.STR &= ~flag; R.STR |= 0x1efe; }
INLINE void SET(UINT16 flag) { R.STR |= flag; R.STR |= 0x1efe; }
INLINE void getdata(UINT8 shift,UINT8 signext)
{
if (opcode_minor & 0x80) memaccess = ind;
else memaccess = dma;
R.ALU = M_RDRAM(memaccess);
if ((signext) && (R.ALU & 0x8000)) R.ALU |= 0xffff0000;
else R.ALU &= 0x0000ffff;
R.ALU <<= shift;
if (opcode_minor & 0x80) {
if ((opcode_minor & 0x20) || (opcode_minor & 0x10)) {
UINT16 tmpAR = R.AR[ARP];
if (opcode_minor & 0x20) tmpAR++ ;
if (opcode_minor & 0x10) tmpAR-- ;
R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (tmpAR & 0x01ff);
}
if (~opcode_minor & 0x08) {
if (opcode_minor & 1) SET(ARP_REG);
else CLR(ARP_REG);
}
}
}
INLINE void getdata_lar(void)
{
if (opcode_minor & 0x80) memaccess = ind;
else memaccess = dma;
R.ALU = M_RDRAM(memaccess);
if (opcode_minor & 0x80) {
if ((opcode_minor & 0x20) || (opcode_minor & 0x10)) {
if ((opcode_major & 1) != ARP) {
UINT16 tmpAR = R.AR[ARP];
if (opcode_minor & 0x20) tmpAR++ ;
if (opcode_minor & 0x10) tmpAR-- ;
R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (tmpAR & 0x01ff);
}
}
if (~opcode_minor & 0x08) {
if (opcode_minor & 1) SET(ARP_REG);
else CLR(ARP_REG);
}
}
}
INLINE void putdata(UINT16 data)
{
if (opcode_minor & 0x80) memaccess = ind;
else memaccess = dma;
if (opcode_minor & 0x80) {
if ((opcode_minor & 0x20) || (opcode_minor & 0x10)) {
UINT16 tmpAR = R.AR[ARP];
if (opcode_minor & 0x20) tmpAR++ ;
if (opcode_minor & 0x10) tmpAR-- ;
R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (tmpAR & 0x01ff);
}
if (~opcode_minor & 0x08) {
if (opcode_minor & 1) SET(ARP_REG);
else CLR(ARP_REG);
}
}
if ((opcode_major == 0x30) || (opcode_major == 0x31)) {
M_WRTRAM(memaccess,(R.AR[data])); }
else M_WRTRAM(memaccess,(data&0xffff));
}
INLINE void putdata_sst(UINT16 data)
{
if (opcode_minor & 0x80) memaccess = ind;
else memaccess = dmapage1;
if (opcode_minor & 0x80) {
if ((opcode_minor & 0x20) || (opcode_minor & 0x10)) {
UINT16 tmpAR = R.AR[ARP];
if (opcode_minor & 0x20) tmpAR++ ;
if (opcode_minor & 0x10) tmpAR-- ;
R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (tmpAR & 0x01ff);
}
}
M_WRTRAM(memaccess,(data&0xffff));
}
void M_ILLEGAL(void)
{
logerror("TMS320C10: PC = %04x, Illegal opcode = %04x\n", (R.PC-1), opcode);
}
/* This following function is here to fill in the void for */
/* the opcode call function. This function is never called. */
static void other_7F_opcodes(void) { }
static void illegal(void) { M_ILLEGAL(); }
static void abst(void)
{
if (R.ACC >= 0x80000000) {
R.ACC = ~R.ACC;
R.ACC++ ;
if (OVM && (R.ACC == 0x80000000)) R.ACC-- ;
}
}
/* ** The manual does not mention overflow with the ADD? instructions *****
** however i implelemted overflow, coz it doesnt make sense otherwise **
** and newer generations of this type of chip supported it. I think ****
** the manual is wrong (apart from other errors the manual has). *******
static void add_sh(void) { getdata(opcode_major,1); R.ACC += R.ALU; }
static void addh(void) { getdata(0,0); R.ACC += (R.ALU << 16); }
*/
static void add_sh(void)
{
tmpacc = R.ACC;
getdata(opcode_major,1);
R.ACC += R.ALU;
if (tmpacc > R.ACC) {
SET(OV_FLAG);
if (OVM) R.ACC = 0x7fffffff;
}
else CLR(OV_FLAG);
}
static void addh(void)
{
tmpacc = R.ACC;
getdata(0,0);
R.ACC += (R.ALU << 16);
R.ACC &= 0xffff0000;
R.ACC += (tmpacc & 0x0000ffff);
if (tmpacc > R.ACC) {
SET(OV_FLAG);
if (OVM) {
R.ACC &= 0x0000ffff; R.ACC |= 0x7fff0000;
}
}
else CLR(OV_FLAG);
}
static void adds(void)
{
tmpacc = R.ACC;
getdata(0,0);
R.ACC += R.ALU;
if (tmpacc > R.ACC) {
SET(OV_FLAG);
if (OVM) R.ACC = 0x7fffffff;
}
else CLR(OV_FLAG);
}
static void and(void)
{
getdata(0,0);
R.ACC &= R.ALU;
R.ACC &= 0x0000ffff;
}
static void apac(void)
{
tmpacc = R.ACC;
R.ACC += R.Preg;
if (tmpacc > R.ACC) {
SET(OV_FLAG);
if (OVM) R.ACC = 0x7fffffff;
}
else CLR(OV_FLAG);
}
static void br(void) { R.PC = M_RDOP_ARG(R.PC); }
static void banz(void)
{
if ((R.AR[ARP] & 0x01ff) == 0) R.PC++ ;
else R.PC = M_RDOP_ARG(R.PC);
R.ALU = R.AR[ARP]; R.ALU-- ;
R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (R.ALU & 0x01ff);
}
static void bgez(void)
{
if (R.ACC >= 0) R.PC = M_RDOP_ARG(R.PC);
else R.PC++ ;
}
static void bgz(void)
{
if (R.ACC > 0) R.PC = M_RDOP_ARG(R.PC);
else R.PC++ ;
}
static void bioz(void)
{
if (R.BIO_pending_irq) R.PC = M_RDOP_ARG(R.PC);
else R.PC++ ;
}
static void blez(void)
{
if (R.ACC <= 0) R.PC = M_RDOP_ARG(R.PC);
else R.PC++ ;
}
static void blz(void)
{
if (R.ACC < 0) R.PC = M_RDOP_ARG(R.PC);
else R.PC++ ;
}
static void bnz(void)
{
if (R.ACC != 0) R.PC = M_RDOP_ARG(R.PC);
else R.PC++ ;
}
static void bv(void)
{
if (OV) {
R.PC = M_RDOP_ARG(R.PC);
CLR(OV_FLAG);
}
else R.PC++ ;
}
static void bz(void)
{
if (R.ACC == 0) R.PC = M_RDOP_ARG(R.PC);
else R.PC++ ;
}
static void cala(void)
{
R.STACK[0] = R.STACK[1];
R.STACK[1] = R.STACK[2];
R.STACK[2] = R.STACK[3];
R.STACK[3] = R.PC & ADDR_MASK;
R.PC = R.ACC & ADDR_MASK;
}
static void call(void)
{
R.PC++ ;
R.STACK[0] = R.STACK[1];
R.STACK[1] = R.STACK[2];
R.STACK[2] = R.STACK[3];
R.STACK[3] = R.PC & ADDR_MASK;
R.PC = M_RDOP_ARG((R.PC-1)) & ADDR_MASK;
}
static void dint(void) { SET(INTM_FLAG); }
static void dmov(void) { getdata(0,0); M_WRTRAM((memaccess+1),R.ALU); }
static void eint(void) { CLR(INTM_FLAG); }
static void in_p(void)
{
R.ALU = M_IN((opcode_major & 7));
putdata((R.ALU & 0x0000ffff));
}
static void lac_sh(void)
{
getdata((opcode_major & 0x0f),1);
R.ACC = R.ALU;
}
static void lack(void) { R.ACC = (opcode_minor & 0x000000ff); }
static void lar_ar0(void) { getdata_lar(); R.AR[0] = R.ALU; }
static void lar_ar1(void) { getdata_lar(); R.AR[1] = R.ALU; }
static void lark_ar0(void) { R.AR[0] = (opcode_minor & 0x00ff); }
static void lark_ar1(void) { R.AR[1] = (opcode_minor & 0x00ff); }
static void larp_mar(void)
{
if (opcode_minor & 0x80) {
if ((opcode_minor & 0x20) || (opcode_minor & 0x10)) {
UINT16 tmpAR = R.AR[ARP];
if (opcode_minor & 0x20) tmpAR++ ;
if (opcode_minor & 0x10) tmpAR-- ;
R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (tmpAR & 0x01ff);
}
if (~opcode_minor & 0x08) {
if (opcode_minor & 0x01) SET(ARP_REG) ;
else CLR(ARP_REG);
}
}
}
static void ldp(void)
{
getdata(0,0);
if (R.ALU & 1) SET(DP_REG);
else CLR(DP_REG);
}
static void ldpk(void)
{
if (opcode_minor & 1) SET(DP_REG);
else CLR(DP_REG);
}
static void lst(void)
{
tmpacc = R.STR;
opcode_minor |= 0x08; /* This dont support next arp, so make sure it dont happen */
getdata(0,0);
R.STR = R.ALU;
tmpacc &= INTM_FLAG;
R.STR |= tmpacc;
R.STR |= 0x1efe;
}
static void lt(void) { getdata(0,0); R.Treg = R.ALU; }
static void lta(void)
{
tmpacc = R.ACC;
getdata(0,0);
R.Treg = R.ALU;
R.ACC += R.Preg;
if (tmpacc > R.ACC) {
SET(OV_FLAG);
if (OVM) R.ACC = 0x7fffffff;
}
else CLR(OV_FLAG);
}
static void ltd(void)
{
tmpacc = R.ACC;
getdata(0,0);
R.Treg = R.ALU;
R.ACC += R.Preg;
if (tmpacc > R.ACC) {
SET(OV_FLAG);
if (OVM) R.ACC = 0x7fffffff;
}
else CLR(OV_FLAG);
M_WRTRAM((memaccess+1),R.ALU);
}
static void mpy(void)
{
getdata(0,0);
if ((R.ALU == 0x00008000) && (R.Treg == 0x8000))
R.Preg = 0xc0000000;
else R.Preg = R.ALU * R.Treg;
}
static void mpyk(void)
{
if (opcode & 0x1000)
R.Preg = R.Treg * ((opcode & 0x1fff) | 0xe000);
else R.Preg = R.Treg * (opcode & 0x1fff);
}
static void nop(void) { }
static void or(void)
{
getdata(0,0);
R.ALU &= 0x0000ffff;
R.ACC |= R.ALU;
}
static void out_p(void)
{
getdata(0,0);
M_OUT((opcode_major & 7), (R.ALU & 0x0000ffff));
}
static void pac(void) { R.ACC = R.Preg; }
static void pop(void)
{
R.ACC = R.STACK[3] & ADDR_MASK;
R.STACK[3] = R.STACK[2];
R.STACK[2] = R.STACK[1];
R.STACK[1] = R.STACK[0];
}
static void push(void)
{
R.STACK[0] = R.STACK[1];
R.STACK[1] = R.STACK[2];
R.STACK[2] = R.STACK[3];
R.STACK[3] = R.ACC & ADDR_MASK;
}
static void ret(void)
{
R.PC = R.STACK[3] & ADDR_MASK;
R.STACK[3] = R.STACK[2];
R.STACK[2] = R.STACK[1];
R.STACK[1] = R.STACK[0];
}
static void rovm(void) { CLR(OVM_FLAG); }
static void sach_sh(void) { putdata(((R.ACC << (opcode_major & 7)) >> 16)); }
static void sacl(void) { putdata((R.ACC & 0x0000ffff)); }
static void sar_ar0(void) { putdata(0); }
static void sar_ar1(void) { putdata(1); }
static void sovm(void) { SET(OVM_FLAG); }
static void spac(void)
{
INT32 tmpPreg = R.Preg;
tmpacc = R.ACC ;
/* if (tmpPreg & 0x8000) tmpPreg |= 0xffff0000; */
R.ACC -= tmpPreg ;
if (tmpacc < R.ACC) {
SET(OV_FLAG);
if (OVM) R.ACC = 0x80000000;
}
else CLR(OV_FLAG);
}
static void sst(void) { putdata_sst(R.STR); }
static void sub_sh(void)
{
tmpacc = R.ACC;
getdata((opcode_major & 0x0f),1);
R.ACC -= R.ALU;
if (tmpacc < R.ACC) {
SET(OV_FLAG);
if (OVM) R.ACC = 0x80000000;
}
else CLR(OV_FLAG);
}
static void subc(void)
{
tmpacc = R.ACC;
getdata(15,0);
tmpacc -= R.ALU;
if (tmpacc < 0) {
R.ACC <<= 1;
SET(OV_FLAG);
}
else R.ACC = ((tmpacc << 1) + 1);
}
static void subh(void)
{
tmpacc = R.ACC;
getdata(0,0);
R.ACC -= (R.ALU << 16);
R.ACC &= 0xffff0000;
R.ACC += (tmpacc & 0x0000ffff);
if ((tmpacc & 0xffff0000) < (R.ACC & 0xffff0000)) {
SET(OV_FLAG);
if (OVM) {
R.ACC = (tmpacc & 0x0000ffff);
R.ACC |= 0x80000000 ;
}
}
else CLR(OV_FLAG);
}
static void subs(void)
{
tmpacc = R.ACC;
getdata(0,0);
R.ACC -= R.ALU;
if (tmpacc < R.ACC) {
SET(OV_FLAG);
if (OVM) R.ACC = 0x80000000;
}
else CLR(OV_FLAG);
}
static void tblr(void)
{
R.ALU = M_RDROM((R.ACC & ADDR_MASK));
putdata(R.ALU);
R.STACK[0] = R.STACK[1];
}
static void tblw(void)
{
getdata(0,0);
M_WRTROM(((R.ACC & ADDR_MASK)),R.ALU);
R.STACK[0] = R.STACK[1];
}
static void xor(void)
{
tmpacc = (R.ACC & 0xffff0000);
getdata(0,0);
R.ACC ^= R.ALU;
R.ACC &= 0x0000ffff;
R.ACC |= tmpacc;
}
static void zac(void) { R.ACC = 0; }
static void zalh(void) { getdata(16,0); R.ACC = R.ALU; }
static void zals(void) { getdata(0 ,0); R.ACC = R.ALU; }
static unsigned cycles_main[256]=
{
/*00*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/*10*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/*20*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/*30*/ 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
/*40*/ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/*50*/ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
/*60*/ 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1,
/*70*/ 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 3, 1, 0,
/*80*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/*90*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/*A0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*B0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*C0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*D0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*E0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*F0*/ 0, 0, 0, 0, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2
};
static unsigned cycles_7F_other[32]=
{
/*80*/ 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 1, 1,
/*90*/ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 1,
};
static opcode_fn opcode_main[256]=
{
/*00*/ add_sh ,add_sh ,add_sh ,add_sh ,add_sh ,add_sh ,add_sh ,add_sh
/*08*/ ,add_sh ,add_sh ,add_sh ,add_sh ,add_sh ,add_sh ,add_sh ,add_sh
/*10*/ ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh
/*18*/ ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh ,sub_sh
/*20*/ ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh
/*28*/ ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh ,lac_sh
/*30*/ ,sar_ar0 ,sar_ar1 ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*38*/ ,lar_ar0 ,lar_ar1 ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*40*/ ,in_p ,in_p ,in_p ,in_p ,in_p ,in_p ,in_p ,in_p
/*48*/ ,out_p ,out_p ,out_p ,out_p ,out_p ,out_p ,out_p ,out_p
/*50*/ ,sacl ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*58*/ ,sach_sh ,sach_sh ,sach_sh ,sach_sh ,sach_sh ,sach_sh ,sach_sh ,sach_sh
/*60*/ ,addh ,adds ,subh ,subs ,subc ,zalh ,zals ,tblr
/*68*/ ,larp_mar ,dmov ,lt ,ltd ,lta ,mpy ,ldpk ,ldp
/*70*/ ,lark_ar0 ,lark_ar1 ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*78*/ ,xor ,and ,or ,lst ,sst ,tblw ,lack ,other_7F_opcodes
/*80*/ ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk
/*88*/ ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk
/*90*/ ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk
/*98*/ ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk ,mpyk
/*A0*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*A8*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*B0*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*B8*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*C0*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*C8*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*D0*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*D8*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*E0*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*E8*/ ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*F0*/ ,illegal ,illegal ,illegal ,illegal ,banz ,bv ,bioz ,illegal
/*F8*/ ,call ,br ,blz ,blez ,bgz ,bgez ,bnz ,bz
};
static opcode_fn opcode_7F_other[32]=
{
/*80*/ nop ,dint ,eint ,illegal ,illegal ,illegal ,illegal ,illegal
/*88*/ ,abst ,zac ,rovm ,sovm ,cala ,ret ,pac ,apac
/*90*/ ,spac ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal ,illegal
/*98*/ ,illegal ,illegal ,illegal ,illegal ,push ,pop ,illegal ,illegal
};
/****************************************************************************
* Reset registers to their initial values
****************************************************************************/
void tms320c10_reset (void *param)
{
R.PC = 0;
R.STR = 0x0fefe;
R.ACC = 0;
R.pending_irq = TMS320C10_NOT_PENDING;
R.BIO_pending_irq = TMS320C10_NOT_PENDING;
}
/****************************************************************************
* Shut down CPU emulation
****************************************************************************/
void tms320c10_exit (void)
{
/* nothing to do ? */
}
/****************************************************************************
* Issue an interrupt if necessary
****************************************************************************/
static int Ext_IRQ(void)
{
if (INTM == 0)
{
logerror("TMS320C10: EXT INTERRUPT\n");
SET(INTM_FLAG);
R.STACK[0] = R.STACK[1];
R.STACK[1] = R.STACK[2];
R.STACK[2] = R.STACK[3];
R.STACK[3] = R.PC & ADDR_MASK;
R.PC = 0x0002;
R.pending_irq = TMS320C10_NOT_PENDING;
return 3; /* 3 clock cycles used due to PUSH and DINT operation ? */
}
return 0;
}
/****************************************************************************
* Execute IPeriod. Return 0 if emulation should be stopped
****************************************************************************/
int tms320c10_execute(int cycles)
{
tms320c10_ICount = cycles;
do
{
if (R.pending_irq & TMS320C10_PENDING)
{
int type = (*R.irq_callback)(0);
R.pending_irq |= type;
}
if (R.pending_irq) {
/* Dont service INT if prev instruction was MPY, MPYK or EINT */
if ((opcode_major != 0x6d) || ((opcode_major & 0xe0) != 0x80) || (opcode != 0x7f82))
tms320c10_ICount -= Ext_IRQ();
}
R.PREPC = R.PC;
CALL_MAME_DEBUG;
opcode=M_RDOP(R.PC);
opcode_major = ((opcode & 0x0ff00) >> 8);
opcode_minor = (opcode & 0x0ff);
R.PC++;
if (opcode_major != 0x07f) { /* Do all opcodes except the 7Fxx ones */
tms320c10_ICount -= cycles_main[opcode_major];
(*(opcode_main[opcode_major]))();
}
else { /* Opcode major byte 7Fxx has many opcodes in its minor byte */
opcode_minr = (opcode & 0x001f);
tms320c10_ICount -= cycles_7F_other[opcode_minr];
(*(opcode_7F_other[opcode_minr]))();
}
}
while (tms320c10_ICount>0);
return cycles - tms320c10_ICount;
}
/****************************************************************************
* Get all registers in given buffer
****************************************************************************/
unsigned tms320c10_get_context (void *dst)
{
if( dst )
*(tms320c10_Regs*)dst = R;
return sizeof(tms320c10_Regs);
}
/****************************************************************************
* Set all registers to given values
****************************************************************************/
void tms320c10_set_context (void *src)
{
if( src )
R = *(tms320c10_Regs*)src;
}
/****************************************************************************
* Return program counter
****************************************************************************/
unsigned tms320c10_get_pc (void)
{
return R.PC;
}
/****************************************************************************
* Set program counter
****************************************************************************/
void tms320c10_set_pc (unsigned val)
{
R.PC = val;
}
/****************************************************************************
* Return stack pointer
****************************************************************************/
unsigned tms320c10_get_sp (void)
{
return R.STACK[3];
}
/****************************************************************************
* Set stack pointer
****************************************************************************/
void tms320c10_set_sp (unsigned val)
{
R.STACK[3] = val;
}
/****************************************************************************
* Return a specific register
****************************************************************************/
unsigned tms320c10_get_reg(int regnum)
{
switch( regnum )
{
case TMS320C10_PC: return R.PC;
/* This is actually not a stack pointer, but the stack contents */
case TMS320C10_STK3: return R.STACK[3];
case TMS320C10_ACC: return R.ACC;
case TMS320C10_STR: return R.STR;
case TMS320C10_PREG: return R.Preg;
case TMS320C10_TREG: return R.Treg;
case TMS320C10_AR0: return R.AR[0];
case TMS320C10_AR1: return R.AR[1];
default:
if( regnum <= REG_SP_CONTENTS )
{
unsigned offset = (REG_SP_CONTENTS - regnum);
if( offset < 4 )
return R.STACK[offset];
}
}
return 0;
}
/****************************************************************************
* Set a specific register
****************************************************************************/
void tms320c10_set_reg(int regnum, unsigned val)
{
switch( regnum )
{
case TMS320C10_PC: R.PC = val; break;
/* This is actually not a stack pointer, but the stack contents */
case TMS320C10_STK3: R.STACK[3] = val; break;
case TMS320C10_STR: R.STR = val; break;
case TMS320C10_ACC: R.ACC = val; break;
case TMS320C10_PREG: R.Preg = val; break;
case TMS320C10_TREG: R.Treg = val; break;
case TMS320C10_AR0: R.AR[0] = val; break;
case TMS320C10_AR1: R.AR[1] = val; break;
default:
if( regnum <= REG_SP_CONTENTS )
{
unsigned offset = (REG_SP_CONTENTS - regnum);
if( offset < 4 )
R.STACK[offset] = val;
}
}
}
/****************************************************************************
* Set NMI line state
****************************************************************************/
void tms320c10_set_nmi_line(int state)
{
/* TMS320C10 does not have a NMI line */
}
/****************************************************************************
* Set IRQ line state
****************************************************************************/
void tms320c10_set_irq_line(int irqline, int state)
{
if (irqline == TMS320C10_ACTIVE_INT)
{
R.irq_state = state;
if (state == CLEAR_LINE) R.pending_irq &= ~TMS320C10_PENDING;
if (state == ASSERT_LINE) R.pending_irq |= TMS320C10_PENDING;
}
if (irqline == TMS320C10_ACTIVE_BIO)
{
if (state == CLEAR_LINE) R.BIO_pending_irq &= ~TMS320C10_PENDING;
if (state == ASSERT_LINE) R.BIO_pending_irq |= TMS320C10_PENDING;
}
}
void tms320c10_set_irq_callback(int (*callback)(int irqline))
{
R.irq_callback = callback;
}
/****************************************************************************
* Return a formatted string for a register
****************************************************************************/
const char *tms320c10_info(void *context, int regnum)
{
static char buffer[16][47+1];
static int which;
tms320c10_Regs *r = context;
which = ++which % 16;
buffer[which][0] = '\0';
if( !context )
r = &R;
switch( regnum )
{
case CPU_INFO_REG+TMS320C10_PC: sprintf(buffer[which], "PC:%04X", r->PC); break;
case CPU_INFO_REG+TMS320C10_SP: sprintf(buffer[which], "SP:%X", 0); /* fake stack pointer */ break;
case CPU_INFO_REG+TMS320C10_STR: sprintf(buffer[which], "STR:%04X", r->STR); break;
case CPU_INFO_REG+TMS320C10_ACC: sprintf(buffer[which], "ACC:%08X", r->ACC); break;
case CPU_INFO_REG+TMS320C10_PREG: sprintf(buffer[which], "P:%08X", r->Preg); break;
case CPU_INFO_REG+TMS320C10_TREG: sprintf(buffer[which], "T:%04X", r->Treg); break;
case CPU_INFO_REG+TMS320C10_AR0: sprintf(buffer[which], "AR0:%04X", r->AR[0]); break;
case CPU_INFO_REG+TMS320C10_AR1: sprintf(buffer[which], "AR1:%04X", r->AR[1]); break;
case CPU_INFO_REG+TMS320C10_STK0: sprintf(buffer[which], "STK0:%04X", r->STACK[0]); break;
case CPU_INFO_REG+TMS320C10_STK1: sprintf(buffer[which], "STK1:%04X", r->STACK[1]); break;
case CPU_INFO_REG+TMS320C10_STK2: sprintf(buffer[which], "STK2:%04X", r->STACK[2]); break;
case CPU_INFO_REG+TMS320C10_STK3: sprintf(buffer[which], "STK3:%04X", r->STACK[3]); break;
case CPU_INFO_FLAGS:
sprintf(buffer[which], "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
r->STR & 0x8000 ? 'O':'.',
r->STR & 0x4000 ? 'M':'.',
r->STR & 0x2000 ? 'I':'.',
r->STR & 0x1000 ? '.':'?',
r->STR & 0x0800 ? 'a':'?',
r->STR & 0x0400 ? 'r':'?',
r->STR & 0x0200 ? 'p':'?',
r->STR & 0x0100 ? '1':'0',
r->STR & 0x0080 ? '.':'?',
r->STR & 0x0040 ? '.':'?',
r->STR & 0x0020 ? '.':'?',
r->STR & 0x0010 ? '.':'?',
r->STR & 0x0008 ? '.':'?',
r->STR & 0x0004 ? 'd':'?',
r->STR & 0x0002 ? 'p':'?',
r->STR & 0x0001 ? '1':'0');
break;
case CPU_INFO_NAME: return "320C10";
case CPU_INFO_FAMILY: return "Texas Instruments 320C10";
case CPU_INFO_VERSION: return "1.02";
case CPU_INFO_FILE: return __FILE__;
case CPU_INFO_CREDITS: return "Copyright (C) 1999 by Quench";
case CPU_INFO_REG_LAYOUT: return (const char*)tms320c10_reg_layout;
case CPU_INFO_WIN_LAYOUT: return (const char*)tms320c10_win_layout;
}
return buffer[which];
}
unsigned tms320c10_dasm(char *buffer, unsigned pc)
{
#ifdef MAME_DEBUG
return Dasm32010( buffer, pc );
#else
sprintf( buffer, "$%04X", TMS320C10_RDOP(pc) );
return 2;
#endif
}